package org.spark.api.utils

import java.time._
import java.time.format.DateTimeFormatter
import java.time.temporal.{ChronoUnit, TemporalAdjusters}
import java.util
import com.google.common.collect.Lists
import org.apache.commons.lang.StringUtils
import scala.collection.JavaConversions._


/**
 * @author LJK
 * @date 2019/10/18 5:34 下午
 */
object DateUtils {

   val formatter = DateTimeFormatter.ofPattern("yyyyMMdd")
   val hourFormatter = DateTimeFormatter.ofPattern("yyyyMMddHH")
   val birthdayFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
   val monthFormatter = DateTimeFormatter.ofPattern("yyyyMM")
   val normalFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")

  def getOneDaySeconds(day: String): Long = {
    LocalDate.parse(day, formatter).atStartOfDay(ZoneId.systemDefault()).toEpochSecond
  }

  def getToday: String = {
    val today: LocalDate = LocalDate.now(ZoneId.systemDefault())
    formatter.format(today)
  }

  def getBeforeDay(day: String, point: Int): String = {
    val date: LocalDate = LocalDate.parse(day, formatter)
    val beforeDate: LocalDate = date.plusDays(point)
    formatter.format(beforeDate)
  }

  def toDayString(crawlTime: Long): String = {
    formatter.format(LocalDateTime.ofInstant(Instant.ofEpochSecond(crawlTime),
      ZoneId.systemDefault()))
  }

  def toHourString(crawlTime: Long): String = {
    hourFormatter.format(LocalDateTime.ofInstant(Instant.ofEpochSecond(crawlTime),
      ZoneId.systemDefault()))
  }

  def getYesterday: String = {
    val yesterday: LocalDate = LocalDate.now(ZoneId.systemDefault())
      .plusDays(-1)
    formatter.format(yesterday)
  }

  def getBeforeYesterday: String = {
    val beforeYesterday: LocalDate = LocalDate.now(ZoneId.systemDefault())
      .plusDays(-2)
    formatter.format(beforeYesterday)
  }

  def getLastWeekStartDate: LocalDate = {
    val today: LocalDate = LocalDate.now(ZoneId.systemDefault())
    val monday: LocalDate = today.`with`(DayOfWeek.MONDAY)
    monday.plusWeeks(-1)
  }

  def getLastWeekEndDate: LocalDate = {
    val today: LocalDate = LocalDate.now(ZoneId.systemDefault())
    val monday: LocalDate = today.`with`(DayOfWeek.MONDAY)
    monday.plusDays(-1)
  }

  def getLastWeekEndString: String = {
    formatter.format(getLastWeekEndDate)
  }

  def getLastWeekStartString: String = {
    formatter.format(getLastWeekStartDate)
  }

  def getLastMonthFirstDay: String = {
    formatter.format(getLastMonthFirstDayDate)
  }

  def getLastMonth: String = {
    monthFormatter.format(getLastMonthFirstDayDate)
  }

  def getLastMonthFirstDayDate: LocalDate = {
    val now = LocalDate.now(ZoneId.systemDefault())
    val monthFirstDay = now.withDayOfMonth(1)
    monthFirstDay.plusMonths(-1)
  }

  def getNowMonthFirstDayDate:LocalDate = {
    val now = LocalDate.now(ZoneId.systemDefault())
    now.withDayOfMonth(1)
  }

  def getNowMonthFirstDay:String = {
    formatter.format(getNowMonthFirstDayDate)
  }

  def getLastMonthEndDay: String = {
    formatter.format(getLastMonthEndDayDate)
  }

  def getLastMonthEndDayDate: LocalDate = {
    val now = LocalDate.now(ZoneId.systemDefault())
    val monthFirstDay = now.withDayOfMonth(1)
    monthFirstDay.plusDays(-1)
  }

  def getLastWeekDays: List[String] = {

    val weekStart = getLastWeekStartDate
    val weekEnd = getLastWeekEndDate

    addDayStringList(weekStart, weekEnd).toList
  }

  def getLastMonthDays: List[String] = {
    val monthStart = getLastMonthFirstDayDate
    val monthEnd = getLastMonthEndDayDate

    addDayStringList(monthStart, monthEnd).toList
  }

  def getAge(birthday: String): Int = {

    birthday match {
      case _ if StringUtils.isNotBlank(birthday) =>
        val birthTime: LocalDate = LocalDate.parse(birthday, birthdayFormatter)
        val now: LocalDate = LocalDate.now()
        val period: Period = Period.between(birthTime, now)
        period.getYears
      case _ => 0
    }
  }

  def getNaturalDateShard(time: Long): (String, String, String) = {
    val localDateTime = LocalDateTime.ofInstant(Instant.ofEpochSecond(time), ZoneId.systemDefault())

    val dayOfWeek: DayOfWeek = localDateTime.getDayOfWeek
    val value = dayOfWeek.getValue
    val (pre, next): (Int, Int) = (value - 1, 7 - value)
    val monday = localDateTime.minusDays(pre)
    val sunday = localDateTime.plusDays(next)

    val day = formatter.format(localDateTime)
    val week = formatter.format(monday) + "-" + formatter.format(sunday)
    val month = monthFormatter.format(localDateTime)

    (day, week, month)
  }

  def getNormalTimeFormat(time: Long): String = {
    val localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault())
    val formatTime = normalFormatter.format(localDateTime)
    formatTime
  }


  def getNaturalWeekDateTimePair(time: Long): (LocalDateTime, LocalDateTime) = {
    val localDateTime = LocalDateTime.ofInstant(Instant.ofEpochSecond(time), ZoneId.systemDefault())
    val dayOfWeek: DayOfWeek = localDateTime.getDayOfWeek
    val value = dayOfWeek.getValue
    val (pre, next): (Int, Int) = (value - 1, 7 - value)
    val monday = localDateTime.minusDays(pre)
    val sunday = localDateTime.plusDays(next)
    (monday, sunday)
  }


  def getNaturalWeek(time: Long): (String, String) = {
    val (monday, sunday) = getNaturalWeekDateTimePair(time)
    (formatter.format(monday), formatter.format(sunday))
  }


  def getNaturalMonthDateTimePair(time: Long): (LocalDateTime, LocalDateTime) = {
    val localDateTime = LocalDateTime.ofInstant(Instant.ofEpochSecond(time), ZoneId.systemDefault())
    val firstDay = localDateTime.withDayOfMonth(1)
    val lastDay = localDateTime.`with`(TemporalAdjusters.lastDayOfMonth())
    (firstDay, lastDay)
  }


  /**
   * 获取所在周的所有日期
   *
   * @param time
   * @return
   */
  def getNaturalWeekDayStringList(time: Long): util.List[String] = {
    val (monday, sunday): (LocalDateTime, LocalDateTime) = getNaturalWeekDateTimePair(time)
    addDayStringList(monday, sunday)
  }

  /**
   * 获取两个时间之间的所有日期
   *
   * @param start
   * @param end
   * @return
   */
  def addDayStringList(start: LocalDateTime, end: LocalDateTime): util.List[String] = {
    val list: util.List[String] = Lists.newArrayList()
    val between = Math.abs(ChronoUnit.DAYS.between(start, end))
    for (i <- 0L to between) {
      val date = start.plusDays(i)
      list.add(formatter.format(date))
    }
    list
  }

  /**
   * 获取两个时间之间的所有日期
   *
   * @param start
   * @param end
   * @return
   */
  def addDayStringList(start: LocalDate, end: LocalDate): util.List[String] = {
    val list: util.List[String] = Lists.newArrayList()
    val between = Math.abs(ChronoUnit.DAYS.between(start, end))
    for (i <- 0L to between) {
      val date = start.plusDays(i)
      list.add(formatter.format(date))
    }
    list
  }

  /**
   * 获取两个时间之间的所有日期
   *
   * @param start
   * @param end
   * @return
   */
  def addDayStringList(start: String, end: String): util.List[String] = {
    val startDate: LocalDate = LocalDate.parse(start, formatter)
    val endDate: LocalDate = LocalDate.parse(end, formatter)
    addDayStringList(startDate, endDate)
  }

  /**
   * 获取传入的时间戳所在的月份的日期列表
   *
   * @param time
   * @return
   */
  def getNaturalMonthDayStringList(time: Long): util.List[String] = {
    val (firstDay, lastDay): (LocalDateTime, LocalDateTime) = getNaturalMonthDateTimePair(time)
    addDayStringList(firstDay, lastDay)
  }

  /**
   * 获取传入时间戳所在的月份的所有周
   *
   * @param time
   * @return
   */
  def getNatualMonthWeekPairList(time: Long): util.List[(String, String)] = {
    val (firstDay, lastDay): (LocalDateTime, LocalDateTime) = getNaturalMonthDateTimePair(time)
    val list: util.List[(String, String)] = Lists.newArrayList()
    for (i <- 0 to lastDay.getDayOfMonth) {
      val date = firstDay.plusDays(i)
      if (date.getDayOfWeek.getValue == DayOfWeek.MONDAY.getValue) {
        val (monday, sunday): (String, String) = (formatter.format(date), formatter.format(date.plusDays(6)))
        list.add((monday, sunday))
      }
    }
    list
  }

  /**
   * 获取自然月
   *
   * @param time
   * @return
   */
  def toMonthString(time: Long): String = {
    monthFormatter.format(LocalDateTime.ofInstant(Instant.ofEpochSecond(time),
      ZoneId.systemDefault()))
  }

  def getRowKeyScanWeekDays: (String, String) = {
    val today: LocalDate = LocalDate.now()
    val monday: LocalDate = today.`with`(DayOfWeek.MONDAY)
    val lastMonday: LocalDate = monday.plusWeeks(-1)
    (formatter.format(lastMonday), formatter.format(monday))
  }

  def getRowKeyScanDays: (String, String) = {
    val today: LocalDate = LocalDate.now()
    val yesterday = today.plusDays(-1)
    (formatter.format(yesterday), formatter.format(today))
  }

  def getRowKeyScanMonthDays: (String, String) = {
    val today: LocalDate = LocalDate.now()
    val monthFirstDay = today.withDayOfMonth(1)
    val lastMonthFirstDay: LocalDate = monthFirstDay.plusMonths(-1)
    (formatter.format(lastMonthFirstDay), formatter.format(monthFirstDay))
  }

  def getLocalDateTime(epochSeconds: Long): LocalDateTime = {
    LocalDateTime.ofInstant(Instant.ofEpochSecond(epochSeconds), ZoneId.systemDefault())
  }

  def getDayOfWeek(epochSeconds: Long): Int ={
    getLocalDateTime(epochSeconds).getDayOfWeek.getValue
  }

  def getHourOfDay(epochSeconds: Long): Int ={
    getLocalDateTime(epochSeconds).getHour
  }


  def parseLocalDate(date: String, formatter: DateTimeFormatter) : LocalDate = {
    LocalDate.parse(date, formatter)
  }

  def parseLocalDateTime(date: String, formatter: DateTimeFormatter): LocalDateTime = {
    LocalDateTime.parse(date, formatter)
  }

  def main(args: Array[String]): Unit = {


    println(getRowKeyScanDays)
    println(getRowKeyScanMonthDays)
    println(getRowKeyScanWeekDays)

  }


}